﻿using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Marmat.Forms
{
    /// <summary>
    /// 用于异步执行方法的操作类。
    /// </summary>
    /// <remarks></remarks>
    public sealed class AsyncHelper
    {

        /// <summary>
        /// 运行异步方法
        /// </summary>
        /// <param name="action"></param>
        public static void Run(Action action)
        {
            var frm = new AsyncHelperForm();
            Custom(frm, action);
        }

        /// <summary>
        /// 运行可取消的异步方法
        /// </summary>
        /// <param name="action">以异步方式执行的工作量。</param>
        /// <param name="cancellationToken">应用以取消工作的取消标记</param>
        public static void Run(Action action, CancellationToken cancellationToken)
        {
            var frm = new AsyncHelperForm();
            Custom(frm, action, cancellationToken);
        }

        /// <summary>
        /// 运行异步方法
        /// </summary>
        /// <param name="action">以异步方式执行的工作量</param>
        public static void Run(Action<AsyncHelperEventArgs> action)
        {
            var frm = new AsyncHelperForm();
            Custom(frm, () => action.Invoke(new AsyncHelperEventArgs(frm)));
        }

        /// <summary>
        /// 运行异步方法
        /// </summary>
        /// <param name="action">以异步方式执行的工作量</param>
        /// <param name="cancellationToken">应用以取消工作的取消标记</param>
        public static void Run(Action<AsyncHelperEventArgs> action, CancellationToken cancellationToken)
        {
            var frm = new AsyncHelperForm();
            Custom(frm, () => action.Invoke(new AsyncHelperEventArgs(frm)), cancellationToken);
        }

        /// <summary>
        /// 运行异步方法
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="func"></param>
        /// <returns></returns>
        public static TResult Run<TResult>(Func<TResult> func)
        {
            var frm = new AsyncHelperForm();
            return Custom(frm, func);
        }

        /// <summary>
        /// 运行异步方法
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="func"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public static TResult Run<TResult>(Func<TResult> func, CancellationToken cancellationToken)
        {
            var frm = new AsyncHelperForm();
            return Custom(frm, func, cancellationToken);
        }

        /// <summary>
        /// 运行异步方法
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="func"></param>
        /// <returns></returns>
        public static TResult Run<TResult>(Func<AsyncHelperEventArgs, TResult> func)
        {
            var frm = new AsyncHelperForm();
            return Custom(frm, () => func.Invoke(new AsyncHelperEventArgs(frm)));
        }

        /// <summary>
        /// 运行异步方法
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="func"></param>
        /// <param name="cancellationToken">应用以取消工作的取消标记</param>
        /// <returns></returns>
        public static TResult Run<TResult>(Func<AsyncHelperEventArgs, TResult> func, CancellationToken cancellationToken)
        {
            var frm = new AsyncHelperForm();
            return Custom(frm, () => func.Invoke(new AsyncHelperEventArgs(frm)), cancellationToken);
        }

        /// <summary>
        /// 运行异步方法
        /// </summary>
        /// <param name="form"></param>
        /// <param name="action"></param>
        public static void Custom(System.Windows.Forms.Form form, Action action)
        {
            using (var frm = form)
            {
                frm.Load += async (sender, e) =>
                {
                    try
                    {
                        await Task.Run(action);
                        frm.DialogResult = DialogResult.OK;
                    }
                    finally
                    {
                        frm.DialogResult = DialogResult.Cancel;
                    }
                };
                frm.ShowDialog();
            }
        }

        /// <summary>
        /// 运行可取消的异步方法
        /// </summary>
        /// <param name="form"></param>
        /// <param name="action">以异步方式执行的工作量。</param>
        /// <param name="cancellationToken">应用以取消工作的取消标记</param>
        public static void Custom(System.Windows.Forms.Form form, Action action, CancellationToken cancellationToken)
        {
            using var frm = form;
            frm.Load += async (sender, e) =>
            {
                try
                {
                    await Task.Run(action, cancellationToken);
                    frm.DialogResult = DialogResult.OK;
                }
                finally
                {
                    frm.DialogResult = DialogResult.Cancel;
                }
            };
            frm.ShowDialog();
        }

        /// <summary>
        /// 运行异步方法
        /// </summary>
        /// <param name="form"></param>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="func"></param>
        /// <returns></returns>
        public static TResult Custom<TResult>(System.Windows.Forms.Form form, Func<TResult> func)
        {
            var result = default(TResult);
            using (var frm = form)
            {
                frm.Load += async (sender, e) =>
                {
                    try
                    {
                        result = await Task.Run(func);
                        frm.DialogResult = DialogResult.OK;
                    }
                    finally
                    {
                        frm.DialogResult = DialogResult.Cancel;
                    }
                };
                frm.ShowDialog();
            }
            return result;
        }

        /// <summary>
        /// 运行异步方法
        /// </summary>
        /// <param name="form"></param>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="func"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public static TResult Custom<TResult>(System.Windows.Forms.Form form, Func<TResult> func, CancellationToken cancellationToken)
        {
            var result = default(TResult);
            using (var frm = form)
            {
                frm.Load += async (sender, e) =>
                {
                    try
                    {
                        result = await Task.Run(func, cancellationToken);
                        frm.DialogResult = DialogResult.OK;
                    }
                    finally
                    {
                        frm.DialogResult = DialogResult.Cancel;
                    }
                };
                frm.ShowDialog();
            }
            return result;
        }
    }
}